const puppeteer = require("puppeteer");
const mergePDFObj = require("./merge-pdf.js");
const fs = require("fs");
const path = require("path");
const dayjs = require("dayjs");
const Stream = require("stream");

// 默认页眉页脚模板
const templateHF = require("./header-footer-template.js");
// 静态文件路径
const staticPath = path.resolve(
  __dirname,
  `../static/${dayjs().format("YYYY_MM_DD_HH_mm_ss测试")}.pdf`
);
let handlingCount = 0; // 正在处理的请求数

/**
 * 初始化浏览器
 * @returns
 */
async function launchBrowser() {
  try {
    let global = {}; // 全局数据
    //初始化浏览器
    const browser = await puppeteer.launch({
      // executablePath: "/opt/google/chrome-linux/chrome-wrapper", //linux系统chrome浏览器位置
      headless: false, //是否开启无头浏览器模式，默认开启;设置为fasle可以打开浏览器窗口模式调试
      /* args: ['--no-sandbox', '--disable-setuid-sandbox', '--enable-accelerated-2d-canvas', '--enable-aggressive-domstorage-flushing'], */
      //浏览器参数配置
      args: [
        "-disable-gpu",
        "-disable-dev-shm-usage",
        "-disable-setuid-sandbox",
        "-no-first-run",
        "-no-sandbox",
        "-no-zygote",
        // "-single-process",
      ],
      devtools: false, //是否打开浏览器的调试工具
      ignoreHTTPSErrors: true, //是否忽略https
      timeout: 120000,
    });
    //获取用于连接到此 browser 的 WebSocket URL。
    const wsAddress = browser.wsEndpoint();
    //转换链接地址未Buffer
    const w_data = Buffer.from(wsAddress);
    global.wsa = w_data;
    global.browser = browser;
    global.puppeteer = puppeteer;
    console.log("chrome内核启动成功");
    return global;
  } catch (e) {
    console.log(e);
  }
}

/**
 * 打开一个新的窗口
 * @param {*} global 全局参数
 * @param global.wsa 用于连接到此 browser 的 WebSocket URL。
 * @returns
 */
async function getNewPage(global) {
  const browser = await puppeteer.connect({
    browserWSEndpoint: global.wsa,
  });
  console.log("open Page");
  return browser.newPage();
}

function setResponse(ctx, data, status, status) {
  ctx.body = {
    data: data,
    status: status,
    message: status,
  };
}

/**
 * 生成 PDF 文件
 */
async function generatePDF(ctx) {
  try {
    // 解析查询参数
    const configData = ctx.request.body; // body参数
    const requestHeader = ctx.request.header; // 请求头参数
    const { pageStyle, pageInfo, pageTemplate, pageCache } = configData; // 解构参数
    console.log("pageInfo", pageInfo);

    // 基础参数判断，是否缺少必要参数
    if (!configData || !pageInfo || (pageInfo && !pageInfo.contentUrl)) {
      setResponse(
        ctx,
        null,
        400,
        "请求参数错误,请检查是否少了pageInfo->contentUrl参数"
      );
      return;
    }

    const launchBrowser = await ctx.launchBrowser; //浏览器缓存参数
    // 连接数 + 1
    ++handlingCount;
    console.log(`正在处理的连接数${handlingCount}`);

    if (handlingCount >= 5) {
      setResponse(ctx, null, 500, "当前请求量过大，请稍后再试");
      return;
    }

    const startTime = dayjs(); // 打印开始时间

    // 缓存处理，设置token等
    if (pageCache) {
      console.log("设置缓存--");
      // 开启一个新的标签页
      const originPage = await getNewPage(launchBrowser);
      let origin = requestHeader.origin;

      // 导航到域名， 等待响应加载
      await originPage.goto(origin, {
        waitUntil: ["load", "networkidle0"],
      });

      //  设置缓存
      await originPage.evaluate((pageCache) => {
        localStorage.clear();
        for (let key in pageCache) {
          localStorage.setItem(key, pageCache[key]);
        }
      }, pageCache);

      originPage.close();
    }

    const page = await getNewPage(launchBrowser); // 开启一个新的标签页
    // 让当前 Tab 页始终处于前台
    await page.bringToFront();
    await page.goto(decodeURIComponent(pageInfo.contentUrl), {
      waitUntil: ["load", "networkidle0"],
    });
    // await page.addStyleTag({
    //   content: "@page { size: 1200px 1698px; }", // 设置页面高度和宽度
    // });

    // await page.evaluate(function () {
    //   return new Promise((resolve) => {
    //     // 通过递归来滚动页面
    //     function scrollPage() {
    //       // { 浏览器窗口可视区域的高度，页面的总高度，已滚动的高度 }
    //       const { clientHeight, scrollHeight, scrollTop } =
    //         document.documentElement;
    //       // 如果滚动高度 + 视口高度 < 总高度，则继续滚动，否则就任务滚动到底部了
    //       if (scrollTop + clientHeight < scrollHeight) {
    //         document.documentElement.scrollTo(0, scrollTop + clientHeight);
    //         // 加一个 setTimeout 来保证滚动的稳定性
    //         setTimeout(() => {
    //           scrollPage();
    //         }, 500);
    //       } else {
    //         // 滚动回顶部，不然计算目录项的页码会有问题
    //         document.documentElement.scrollTo(0, 0);
    //         resolve();
    //       }
    //     }
    //     scrollPage();
    //   });
    // });

    // 将当前页打印成 PDF 文件。不设置 path，文件将会保存在内存中
    let pdfConfig = {
      // 以 A4 纸的尺寸来打印 PDF
      format: "A4",
      // 设置 PDF 文件的页边距，避免内容完全贴边
      margin: {
        right: 40,
        left: 40,
        top: 40,
        bottom: 40,
      },
      // 开启页眉、页脚
      displayHeaderFooter: !!pageTemplate.isHasTemplate,
      // 通过 HTML 模版字符串自定义页眉、页脚
      headerTemplate: templateHF.headerTemplate(),
      footerTemplate: templateHF.footerTemplate(),
      // 打印的时候打印背景色
      preferCSSPageSize: true, // 页面优先级声明CSS
      printBackground: true, // 是否打印背景，CSS
      timeout: 0,
    };

    if (pageTemplate.isHasTemplate) {
      pdfConfig.headerTemplate = pageTemplate.headerTemplate;
      pdfConfig.footerTemplate = pageTemplate.footerTemplate;
    }

    if (pageStyle && pageStyle.marginBottom != null) {
      pdfConfig.margin.bottom = pageStyle.marginBottom;
    }

    if (pageStyle && pageStyle.marginTop != null) {
      pdfConfig.margin.top = pageStyle.marginTop;
    }

    if (pageStyle && pageStyle.marginLeft != null) {
      pdfConfig.margin.left = pageStyle.marginLeft;
    }

    if (pageStyle && pageStyle.marginRight != null) {
      pdfConfig.margin.right = pageStyle.marginRight;
    }

    const contentBuffer = await page.pdf(pdfConfig);

    console.log("----内容处理完成----");

    let coverBuffer, lastPageBuffer;

    // 封面
    if (pageInfo.coverUrl) {
      const coverPage = await getNewPage(launchBrowser); // 开启一个新的标签页
      // 让当前 Tab 页始终处于前台
      await coverPage.bringToFront();
      await coverPage.goto(decodeURIComponent(pageInfo.coverUrl), {
        waitUntil: ["load", "networkidle0"],
      });
      coverBuffer = await coverPage.pdf({
        format: "A4",
        printBackground: true,
        preferCSSPageSize: true, // 页面优先级声明CSS
      });
      console.log("----封面处理完成----");
      coverPage.close();
    }

    // 尾页
    if (pageInfo.lastPageUrl) {
      const lastPage = await getNewPage(launchBrowser); // 开启一个新的标签页
      // 让当前 Tab 页始终处于前台
      await lastPage.bringToFront();
      await lastPage.goto(decodeURIComponent(pageInfo.lastPageUrl), {
        waitUntil: ["load", "networkidle0"],
      });
      lastPageBuffer = await lastPage.pdf({
        format: "A4",
        printBackground: true,
        preferCSSPageSize: true, // 页面优先级声明CSS
      });
      lastPage.close();
      console.log("----尾页处理完成----");
    }

    let pdfBuffer = contentBuffer;
    if (coverBuffer && lastPageBuffer) {
      // 合并三份 PDF
      pdfBuffer = await mergePDFObj.mergePDF(
        coverBuffer,
        contentBuffer,
        lastPageBuffer
      );
    }

    if (coverBuffer && !lastPageBuffer) {
      // 合并两份 PDF--只有封面
      pdfBuffer = await mergePDFObj.mergePDF(coverBuffer, contentBuffer, null);
    }

    if (!coverBuffer && lastPageBuffer) {
      // 合并两份 PDF--只有尾页
      pdfBuffer = await mergePDFObj.mergePDF(
        null,
        contentBuffer,
        lastPageBuffer
      );
    }

    console.log("----pdf合并完成----");

    // 将合并后的终版 PDF 文件写盘
    fs.writeFileSync(staticPath, pdfBuffer);

    const endTime = dayjs(); // 获取结束时间
    // 连接数减一
    --handlingCount;
    console.log(`生成时间： ${endTime.diff(startTime, "second", true)}s`); // 生成耗时

    // 关闭页面
    await page.close();
    //   await browser.close();

    // 将Buffer转换为可读流
    const readable = new Stream.Readable({
      read() {
        this.push(Buffer.from(pdfBuffer));
        this.push(null); // 表示流的结束
      },
    });
    // 设置响应类型，根据你的文件类型更改，比如'application/pdf'
    ctx.set("Content-Type", "application/pdf");
    // 将文件流作为响应体返回
    ctx.body = readable;
  } catch (error) {
    // 连接数减一
    --handlingCount;
    console.log("error:", error);
    setResponse(ctx, null, 500, "生成失败,请检查参数或者重新生成");
  }
}

module.exports = {
  generatePDF,
  launchBrowser,
  getNewPage,
};
